package crack

import (
	"fmt"
	"net"
	"strconv"
	"strings"
	"time"
)

// Mongodbcon 此函数参考fscan项目感谢
func Mongodbcon(ip, port string) {
	packet1 := []byte{
		0x69, 0x00, 0x00, 0x00, // messageLength
		0x39, 0x00, 0x00, 0x00, // requestID
		0x00, 0x00, 0x00, 0x00, // responseTo
		0xdd, 0x07, 0x00, 0x00, // opCode OP_MSG
		0x00, 0x00, 0x00, 0x00, // flagBits
		0x00, 0x54, 0x00, 0x00, 0x00, 0x02, 0x67, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x00, 0x10, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x02, 0x24, 0x64, 0x62, 0x00, 0x06, 0x00, 0x00, 0x00, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x00, 0x03, 0x6c, 0x73, 0x69, 0x64, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x05, 0x69, 0x64, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x6e, 0x81, 0xf8, 0x8e, 0x37, 0x7b, 0x4c, 0x97, 0x84, 0x4e, 0x90, 0x62, 0x5a, 0x54, 0x3c, 0x93, 0x00, 0x00,
	}
	//op_query
	packet2 := []byte{
		0x48, 0x00, 0x00, 0x00, // messageLength
		0x02, 0x00, 0x00, 0x00, // requestID
		0x00, 0x00, 0x00, 0x00, // responseTo
		0xd4, 0x07, 0x00, 0x00, // opCode OP_QUERY
		0x00, 0x00, 0x00, 0x00, // flags
		0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x24, 0x63, 0x6d, 0x64, 0x00, // fullCollectionName admin.$cmd
		0x00, 0x00, 0x00, 0x00, // numberToSkip
		0x01, 0x00, 0x00, 0x00, // numberToReturn
		// query db.adminCommand({getLog: "startupWarnings"})
		0x21, 0x00, 0x00, 0x00, 0x2, 0x67, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x00, 0x10, 0x00, 0x00, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x57, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x00,
	}

	realhost := fmt.Sprintf("%s:%v", ip, port)

	checkUnAuth := func(address string, packet []byte) (string, error) {
		conn, err := net.DialTimeout("tcp", realhost, time.Duration(3)*time.Second)
		if err != nil {
			return "", err
		}
		defer func() {
			if conn != nil {
				conn.Close()
			}
		}()
		err = conn.SetReadDeadline(time.Now().Add(time.Duration(3) * time.Second))
		if err != nil {
			return "", nil
		}
		_, err = conn.Write(packet)
		if err != nil {
			return "", err
		}
		reply := make([]byte, 1024)
		count, err := conn.Read(reply)
		if err != nil {
			return "", err
		}
		return string(reply[0:count]), nil
	}

	reply, err := checkUnAuth(realhost, packet1)
	if err != nil {
		reply, err = checkUnAuth(realhost, packet2)
		if err != nil {
			return
		}
	}
	if strings.Contains(reply, "totalLinesWritten") {
		intport, _ := strconv.Atoi(port)
		end(ip, "未授权访问", "", intport, "MongoDB")
	}
	return
}
